const crypto = require('crypto');
require('dotenv').config();
const express = require('express');
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const axios = require('axios');
const cors = require('cors');
const path = require('path');

// 环境变量预校验
if (!process.env.JWT_SECRET || process.env.JWT_SECRET.length < 32) {
  throw new Error('JWT_SECRET 必须设置为至少 32 位的安全字符串');
}

const app = express();
app.use(express.json());
app.use(cors());

app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, 'public', 'logs.html'));
});


// 增强版数据库连接
const createDBConnection = (uri, name) => {
  const conn = mongoose.createConnection(uri, {
    connectTimeoutMS: 5000,
    socketTimeoutMS: 45000,
    retryWrites: true,
    family: 4,
    serverSelectionTimeoutMS: 5000,
    heartbeatFrequencyMS: 10000  // 心跳检测频率
  });

  let isConnected = false;
  let retryCount = 0;

  const connectWithRetry = async () => {
    try {
      await conn.asPromise();
      isConnected = true;
      retryCount = 0;
      console.log(`${name} DB 已连接`);
    } catch (err) {
      if (retryCount < 5) {
        retryCount++;
        console.log(`${name} DB 连接失败，第 ${retryCount} 次重试...`);
        setTimeout(connectWithRetry, 2000 * retryCount);
      } else {
        console.error(`${name} DB 最终连接失败:`, err.message);
      }
    }
  };

  conn.on('error', err => {
    if (!isConnected) {
      console.error(`${name} DB 初始连接错误:`, err.message);
    } else {
      console.error(`${name} DB 连接异常:`, err.message);
    }
  });

  connectWithRetry();
  return conn;
};

// 数据库连接实例
const emailDB = createDBConnection(
  process.env.EMAIL_DB_URI || 'mongodb://127.0.0.1:27017/email_users',
  '邮箱'
);

const wechatDB = createDBConnection(
  process.env.WECHAT_DB_URI || 'mongodb://127.0.0.1:27017/wechat_users',
  '微信'
);

// Schema 定义
const createUserSchema = () => new mongoose.Schema({
  createdAt: { type: Date, default: Date.now }
});

// 邮箱用户模型
const EmailUserSchema = createUserSchema();
EmailUserSchema.add({
  email: { 
    type: String, 
    required: [true, '邮箱不能为空'],
    unique: true,
    validate: {
      validator: v => /^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$/.test(v),
      message: '邮箱格式无效'
    }
  },
  password: { 
    type: String, 
    required: [true, '密码不能为空'],
    minlength: [6, '密码至少需要6位']
  }
});
const EmailUser = emailDB.model('User', EmailUserSchema);

// 微信用户模型
const WechatUserSchema = createUserSchema();
WechatUserSchema.add({
  openid: { 
    type: String, 
    required: true,
    unique: true 
  },
  unionid: String,
  nickname: String,
  avatar: String
});
const WechatUser = wechatDB.model('User', WechatUserSchema);

// JWT 生成
const generateToken = (user) => {
  return jwt.sign(
    { 
      id: user._id, 
      type: user instanceof EmailUser ? 'email' : 'wechat',
      iss: 'your-app-name' // 签发者标识
    },
    process.env.JWT_SECRET,
    { 
      expiresIn: '1h',
      algorithm: 'HS256' // 明确指定算法
    }
  );
};

// 邮箱认证处理
const handleEmailAuth = async (req, res, isLogin = false) => {
  try {
    const { email, password } = req.body;
    
    // 参数校验
    if (!email || !password) {
      return res.status(400).json({ 
        code: 'MISSING_PARAMETERS',
        message: '缺少 email 或 password 参数' 
      });
    }

    // 邮箱格式验证（Schema 已包含，此处为二次验证）
    if (!EmailUserSchema.path('email').validators.some(v => v.validator(email))) {
      return res.status(400).json({
        code: 'INVALID_EMAIL',
        message: '邮箱格式无效'
      });
    }

    const user = await EmailUser.findOne({ email });
    
    if (isLogin) {
      if (!user) return res.status(404).json({ 
        code: 'USER_NOT_FOUND',
        message: '用户不存在' 
      });
      
      const isMatch = await bcrypt.compare(password, user.password);
      if (!isMatch) return res.status(400).json({ 
        code: 'INVALID_CREDENTIALS',
        message: '密码错误' 
      });
    } else {
      if (user) return res.status(409).json({ 
        code: 'USER_EXISTS',
        message: '邮箱已被注册' 
      });
      
      if (password.length < 6) return res.status(400).json({
        code: 'WEAK_PASSWORD',
        message: '密码至少需要6位'
      });

      const hashedPassword = await bcrypt.hash(password, 12);
      const newUser = await EmailUser.create({ email, password: hashedPassword });
      return res.status(201).json({ 
        token: generateToken(newUser), 
        userId: newUser._id 
      });
    }

    res.json({ 
      token: generateToken(user), 
      userId: user._id 
    });
  } catch (error) {
    res.status(500).json({ 
      code: 'SERVER_ERROR',
      message: `操作失败: ${error.message}` 
    });
  }
};

// 路由注册
app.post('/api/email/register', (req, res) => handleEmailAuth(req, res));
app.post('/api/email/login', (req, res) => handleEmailAuth(req, res, true));

// 微信认证
const WECHAT_CONFIG = {
  appId: process.env.WECHAT_APP_ID,
  appSecret: process.env.WECHAT_APP_SECRET,
  redirectUri: process.env.WECHAT_REDIRECT_URI
};

app.get('/api/wechat/auth', (req, res) => {
  const authUrl = new URL('https://open.weixin.qq.com/connect/qrconnect');
  authUrl.searchParams.append('appid', WECHAT_CONFIG.appId);
  authUrl.searchParams.append('redirect_uri', WECHAT_CONFIG.redirectUri);
  authUrl.searchParams.append('response_type', 'code');
  authUrl.searchParams.append('scope', 'snsapi_login');
  
  // 使用安全的随机数生成 state
  authUrl.searchParams.append('state', crypto.randomBytes(16).toString('hex')); // 已修复
  
  res.redirect(authUrl.toString() + '#wechat_redirect');
});

app.get('/api/wechat/callback', async (req, res) => {
  try {
    const { code, error, error_description } = req.query;
    
    // 处理错误响应
    if (error) {
      return res.redirect(`/error?code=WECHAT_${error}&msg=${encodeURIComponent(error_description)}`);
    }

    // 参数校验
    if (!code) {
      return res.redirect('/error?code=MISSING_CODE&msg=缺少授权码');
    }

    // 获取 access_token
    const { data: tokenData } = await axios.get(
      `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${WECHAT_CONFIG.appId}&secret=${WECHAT_CONFIG.appSecret}&code=${code}&grant_type=authorization_code`
    );

    // 验证 access_token
    if (!tokenData.access_token || !tokenData.openid) {
      throw new Error('无效的微信响应');
    }

    // 获取用户信息
    const { data: userInfo } = await axios.get(
      `https://api.weixin.qq.com/sns/userinfo?access_token=${tokenData.access_token}&openid=${tokenData.openid}`
    );

    // 数据校验
    if (userInfo.errcode) {
      throw new Error(`微信用户信息错误: ${userInfo.errmsg}`);
    }

    // 创建/更新用户
    const user = await WechatUser.findOneAndUpdate(
      { openid: tokenData.openid },
      {
        unionid: userInfo.unionid,
        nickname: userInfo.nickname,
        avatar: userInfo.headimgurl
      },
      { 
        upsert: true, 
        new: true,
        setDefaultsOnInsert: true 
      }
    );

    // 生成 token
    const token = generateToken(user);
    res.redirect(`${process.env.CLIENT_URL}/login?token=${encodeURIComponent(token)}`);
  } catch (error) {
    console.error('微信登录错误:', error);
    res.redirect(`/error?code=WECHAT_FAILED&msg=${encodeURIComponent(error.message)}`);
  }
});

// 统一错误处理中间件
app.use((err, req, res, next) => {
  console.error('全局错误:', err.stack);
  res.status(500).json({
    code: 'UNKNOWN_ERROR',
    message: '系统发生未知错误'
  });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`服务已启动，端口：${PORT}`));